package com.bang.study.day02;

import com.bang.study.day01.InsertionSort;
import com.bang.study.util.ArrayUtil;

/**
 * @Auther: Bang
 * @Date: 2019/9/21 0021 10:18
 * @Description: 快速排序
 * @描述: 快速排序使用分治法来把一个串（list）分为两个子串（sub-lists）。具体算法描述如下：
 * 1. 从数列中挑出一个元素，称为 “基准”（pivot）；
 * 2. 重新排序数列，所有元素比基准值小的摆放在基准前面，所有元素比基准值大的摆在基准的后面
 *  （相同的数可以到任一边）。在这个分区退出之后，该基准就处于数列的中间位置。
 *    这个称为分区（partition）操作；
 * 3. 递归地（recursive）把小于基准值元素的子数列和大于基准值元素的子数列排序。
 * @算法分析: 最佳情况：T(n) = O(nlogn)   最差情况：T(n) = O(n2)   平均情况：T(n) = O(nlogn)　
 * 快速排序的基本思想：通过一趟排序将待排记录分隔成独立的两部分，
 * 其中一部分记录的关键字均比另一部分的关键字小，则可分别对这两部分记录继续进行排序，
 * 以达到整个序列有序。 
 */
public class QuickSort {


    /**
     * 快速排序
     *
     * @param arr
     */
    public static void sort(Integer[] arr) {
        quickSort(arr, 0, arr.length - 1);
    }

    /**
     * 对数组arr[l,r]快速排序
     * @param arr
     * @param l
     * @param r
     */
    private static void  quickSort(Integer[] arr, int l, int r) {
//        if (l>=r) {
//            return;
//        }
        if (r - l <= 16) {
            InsertionSort.insertSort(arr, l, r);
        }
        else{
          int p= partition(arr,l,r);
            quickSort(arr, l, p - 1);
            quickSort(arr, p+1, r);
        }
    }

    /**
     * 将arr进行分割,返回数组中心点 pivot
     *   arr[l..pivot-1] < arr[pivot] < arr[pivot+1, r]
     * @param arr
     * @param l 左边界
     * @param r 右边界
     * @return 数组中心点
     */
    private static int partition(Integer[] arr, int l, int r) {
        Integer pivot = arr[l];
        int j = l;
        for (int i = l + 1; i <= r; i++) {
            if (arr[i] < pivot) {
                j++;
                swap(arr, i, j);
            }
        }
        swap(arr, j, l);
        return j;
    }

    private static void  swap(Integer[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static void main(String[] args) {
        Integer[] array = ArrayUtil.generateRandomArray(10, 0, 200);
        ArrayUtil.printArray(array,10);
        sort(array);
        ArrayUtil.printArray(array, 10);
    }
}
